# 16. 文件操作
# 初始文件操作
使用Python来读写文件是非常简单的操作,可以使用open()函数来打开一个文件
获取文件句柄,然后通过文件句柄就可以进行各种各样的操作
根据打开方式的不同能够执行的操作也有有相应的差异
打开文件的方式:
- r (读取文件)
- w (写入,如果文件存在则清空所有内容,如果文件不存在则创建生成)
- a (追加写入文件内容,默认从结尾写入,不会清空文件原来数据,文件不存在则创建生成)
- r+ (读写操作,需要先读在写)
- w+ (写读操作,需要先写后读,这样就会读不出来,需要使用seek()函数,就可以读出来)
- a+(不常用)
- rb (读取文件以bytes类型显示)
- wb (bytes类型数据写入,如果文件存在则清空所有内容,如果文件不存在则创建生成)
- ab (追加写入bytes类型数据到文件内容,默认从结尾写入,不会清空文件原来数据,文件不存在则创建生成)
- r+b (不常用)
- w+b(不常用)
- a+b(不常用)
# 开启文件句柄 - open()
文件句柄是用来操作文件的
格式:open("文件名",选项)
选项:
1. mode="" 打开文件的方式权限
2. encoding="" 使用什么编码打开文件(解码)
# 关闭文件句柄 - close()
关闭文件句柄,建议操作文件完毕后,需要关闭文件句柄
格式:变量.close()
so.close()
# 刷新文件 - flush()
如果在追加或定入文件后,如果没有系统有一定的延时,数据还没有完整追加或写入文件,就被关了,这样的后果想想就知道了
可以使用flush()函数,强制刷新追加或定入文件,避免文件追加或写入不完整、
格式:变量.flush()
so.flush()
# 路径
文件存放的路径
# 相对路径
相对于你当前程序所在的文件目录
- 如果不写 / 等 就代表当前目录
- ../ 表示上一层目录
# 绝对路径
- 从磁盘根目录开始找起
- 互联网的绝对路径
# 只读(r,rb)
操作文件,以只读方式,如果文件不存在 报错
格式:变量.read()
r 操作
r 是读取文件内容的操作
so = open("文件",mode="r",encoding="utf-8")
wo = so.read()
print(wo)
so.close()
执行结果:
手游欢迎你
以上实例,记得使用完文件后要记得关闭文件句柄,文件存储在本目录下,如果存放在别的目录,建议使用相对路径
rb 操作
rb 读取出来的数据是bytes类型,所有在rb模式下,不能有encoding选项
rb 的作用:在读取非文件的时候,比如读取MP3,图像,视频等信息的时候就需要用到
rb 因为这种数据没办法直接显示出来 ,文件上传下载的时候还会用到
直播中实际就是这种数据
so = open("文件",mode="rb")
wo = so.read()
print(wo)
so.close()
执行结果:
b'\xe6\x89\x8b\xe6\xb8\xb8\xe6\xac\xa2\xe8\xbf\x8e\xe4\xbd\xa0'
# 读取文件的方法和方式
# 指定范围读取 - read(n)
read(n) 读取n个字符
如果是 rb 模式,读取出来的是 n 个字节
以 1 为开头
注意:开始读取是,是从头开始读的,如果再次读取,那么会在上一次读取的位置上在去读
格式:变量 = 变量.read(n)
# r 模式单次读取
so = open("文件",mode="r",encoding="utf-8")
wo = so.read(3)
print(wo)
so.close()
执行结果:
手游欢
以上实例,使用指定范围 3 读取,从开头到第3个字符结束
# rb 模式单次读取
so = open("文件",mode="rb")
wo = so.read(3)
print(wo)
so.close()
执行结果:
b'\xe6\x89\x8b'
以上实例,效果跟上面的实例一样,只是得到的值为bytes类型的数据
# r 模式的多次读取
so = open("文件",mode="r",encoding="utf-8")
wo = so.read(2)
wo1 = so.read(2)
print("第一次读取:",wo)
print("第二次读取:",wo1)
so.close()
执行结果:
第一次读取: 手游
第二次读取: 欢迎
以上实例,开始读取是,是从头开始读的,如果再次读取,那么会在上一次读取的位置上在去读
# 一行一行读取 - readline()
一次读取一行数据
注意:在readline() 结尾都会带有一个\n ,每次读取出来的数据尾部都会有一个\n,可以使用strip() 方法去掉 \n或空格
默认是从第一行开始读,如果还要再次读,就会根据上一次读的位置来分配这次的位置
如果使用strip()函数,去除的话,那么类型会变成列表
格式:变量 = 变量.readline()
so = open("文件",mode="r",encoding="utf-8")
wo = so.readline()
wo1 = so.readline()
wo2 = so.readline()
wo3 = so.readline()
wo4 = so.readline()
print("第一次读取:",wo.split())
print("第二次读取:",wo1)
print("第三次读取:",wo2)
print("第四次读取:",wo3)
print("第五次读取:",wo4)
so.close()
执行结果:
第一次读取: ['手']
第二次读取: 游
第三次读取: 欢
第四次读取: 迎
第五次读取: 你
# for循环
so = open("文件",mode="r",encoding="utf-8")
for line in so:
print(line)
so.close()
执行结果:
手游欢迎你
手游欢迎你
手游欢迎你
手游欢迎你
手游欢迎你
手游欢迎你
手游欢迎你
# 文件内容全部转成列表 - readlines()
将每一行形成一个元素放在一个列表中,将所有的内容都读取出来,请注意内存
格式:变量 = 变量. readlines()
so = open("文件",mode="r",encoding="utf-8")
wo = so.readlines()
print(wo)
so.close()
执行结果:
['手\n', '游\n', '欢\n', '迎\n', '你']
for循环
so = open("文件",mode="r",encoding="utf-8")
wo = so.readlines()
for i in wo:
print(i.strip())
so.close()
执行结果:
手
游
欢
迎
你
# 循环读取 - for循环
通过for循环每次读取一行内容,不会产生内存溢出的问题
so = open("文件",mode="r",encoding="utf-8")
for i in so:
print(i.strip())
so.close()
执行结果:
手
游
欢
迎
你
# 只写(w,wb)
如果写入的时候没有对应的文件,就会创建文件
如果文件存在,就会将原件中原来的内容删除,再写入新内容
格式:变量.write(值)
w 模式
so = open("美女",mode="w",encoding="utf-8")
so.write("化妆是人,遇水是鬼")
so.flush()
so.close()
so = open("美女",mode="r",encoding="utf-8")
wo = so.read()
print(wo)
so.close()
执行结果:
化妆是人,遇水是鬼
以上实例,执行完毕后,如果文件不存在,会在当前目录下创建文件并写入
wb 模式
wb模式,是将bytes类型的数据写入文件中,如果是值,需要使用encode()进行解码
so = open("美女",mode="wb")
so.write("化妆是人,遇水是鬼1".encode("utf-8"))
so.flush()
so.close()
so = open("美女",mode="r",encoding="utf-8")
wo = so.read()
print(wo)
so.close()
执行结果:
化妆是人,遇水是鬼1
以上实例,执行完毕后,如果文件不存在,会在当前目录下创建文件并写入
# 追加(a,ab)
追加,写入的内容会追加到文件的结尾处
如果文件不存在,默认会生成文件并追加写入数据
格式:变量.write(值)
a 模式
so = open("美女",mode="a",encoding="utf-8")
so.write("你是人是鬼")
so.flush()
so.close()
so = open("美女",mode="r",encoding="utf-8")
wo = so.read()
print(wo)
so.close()
执行结果:
化妆是人,遇水是鬼1你是人是鬼你是人是鬼
以上实例,执行完毕后,如果文件不存在,会在当前目录下创建文件并追加 写入
ab 模式
ab模式,是将bytes类型的数据追加写入文件中,如果是值,需要使用encode()进行解码
so = open("美女",mode="ab")
so.write("你是人是鬼".encode("utf-8"))
so.flush()
so.close()
so = open("美女",mode="r",encoding="utf-8")
wo = so.read()
print(wo)
so.close()
执行结果:
化妆是人,遇水是鬼1你是人是鬼
以上实例,执行完毕后,如果文件不存在,会在当前目录下创建文件并追加 写入
# 读写(r+)
对于读写模式,必须是先读,因为默认光标是在开头的,写入就需要到结尾处
注意:在r+模式中,必须是要先读取,然后再写入
关于r+ 有个深坑,在r+模式下,如果读取了内容,无论读取内容多少,光标显示的是多少,再写入都是在结尾进行的操作
so = open("美女",mode="r+",encoding="utf-8")
wo = so.read()
so.write("你好,大家好")
print(wo)
so.flush()
so.close()
执行结果:
你好,大家好
# 写读(w+)
对于写读模式,先将文件中所有内容清空,然后在定稿,最后读取,但是读取的内容是空的
可以先写后,光标的位置就在文件内容的结尾,在读就没能读出什么东西来
如果想要读得出东西来,就要使用seek()函数
so = open("美女",mode="w+",encoding="utf-8")
so.write("你好,大家好")
so.seek(0)
wo = so.read()
print(wo)
so.flush()
so.close()
执行结果:
你好,大家好
# 光标位置移动 - seek()
光标?,光标就是在操作文件中当前位置的所在处
seek(),可以指定光标移动到n个位置中
注意:移动的单位是byte字节,如果编码为UTF-8的中文部分,3个节点 = 一个中文
移动到开头:seek(0)
移动到结尾:seek(0,2)
seek()的第一个参数是不可动的,固定为0
seek()的第二个参数表示的是从那个位置进行偏移,如果不填,默认是0
seek()的第二个参数:
- 0 :为开头
- 1:为当前位置
- 2:为结尾
# 光标移动至开头
so = open("文件",mode="r+",encoding="utf-8")
so.seek(0)
wo = so.read()
print(wo)
so.close()
执行结果:
手游欢迎你
# 光标移动至结尾
so = open("文件",mode="r+",encoding="utf-8")
so.seek(0,2)
wo = so.read()
print(wo)
so.close()
执行结果:
# 查看光标的当前位置 - tell()
可以通过tell()来查看光标的当前位置
注意:通过tell() 查出来的是以byte字节为单位,如果编码为UTF-8的中文部分,3个节点 = 一个中文
格式:变量.tell()
so = open("文件",mode="r+",encoding="utf-8")
so.seek(0,1)
wo = so.read(3)
print(so.tell())
so.close()
执行结果:
9
# 截断文件内容 - truncate()
如果要使用截断操作,要先挪动光标,挪动到你想截断的僧,然后再进行截断
默认是截断当前光标位置后的所有内容
关于truncate(n), 如果给出了了n. 则从开头开头进⾏截断, 如果不给n, 则从当前位置截断. 后面的内容将会被删除
格式:变量.truncate()
截断文件中除了前两位的字符,其他都截断
so = open("文件",mode="r+",encoding="utf-8")
so.seek(6)
so.truncate()
so.seek(0)
wo = so.read()
print(wo)
so.flush()
so.close()
执行结果:
手游
# 指定保留字符数截断
注意:截断的单位是byte字节,如果编码为UTF-8的中文部分,3个节点 = 一个中文
保留前3位字符
so = open("文件",mode="r+",encoding="utf-8")
so.truncate(9)
so.seek(0)
wo = so.read()
print(wo)
so.flush()
so.close()
执行结果:
手游欢
# 文件修改,通过 r+ 跟 w 模式 修改文件
so = open("文件",mode="r+",encoding="utf-8")
wo = so.read()
sh = wo.replace("我","你")
ss = open("文件",mode="w",encoding="utf-8")
so.write(sh)
so.flush()
so.close()
加载要修改的文件,打开文件模式为:r+
读取文件内容到内存中
通过字符串函数:replace(), 修改你要修改的内容,实际修改在内存中修改
在次加载要修改的文件,打开文件模式为:w
写入在内存中修改完毕的数据,因为 w 模式的特殊性:写入会清空文件的所有内容,也相当覆盖
刷新文件句柄
关闭文件句柄
以上实例,这种方式没办法使用for循环一行一行的读取修改,请使用者三思
# 文件的修改以及另一种打开文件句柄的方式
文件修改,实际只能将文件中的内容读取到内存中,将信息修改完毕,然后写入另一个文件中,把源文件删除,将新文件的名字改成老文件的名字
文件修改需要应用一个新的打开文件方式,os模块
如果要一次打开多个文件,可以使用 , 逗号来分隔 open
格式:with open("文件名",mode="打开文件的方式权限",encoding="用什么编码格式打开文件") as 变量名 :
格式:os.remove(文件名) ## 删除文件
格式:os.rename("文件名","新文件名") ## 文件名更改
import os
with open("文件",mode="r",encoding="utf-8") as so , open("文件_os",mode="w",encoding="utf-8") as wo:
sh = so.read()
ssh = sh.replace("你","我")
wo.write(ssh)
os.remove("文件")
os.rename("文件_os","文件")
加载OS模块
使用另一种打开文件的方式,打开二个文件,1:为要修改的文件,2:临时修改替换文件,用 , 逗号分隔
读取要修改的文件
修改内存中读取过的文件数据,使用字符串函数,replace()替换
将修改完的数据写入 2 文件中(临时修改替换文件)
使用os自带的函数,删除 1 文件(要修改的文件)
使用os自带的函数,更改 2 文件的文件名 (临时修改替换文件)
以上实例,读取文件的时候是将文件的所有内容一次读取,这样可能会有内存溢出,建议一行一行读取操作
一行一行读取修改文件内容
import os
with open("文件",mode="r",encoding="utf-8") as so , open("文件_os",mode="w",encoding="utf-8") as wo:
for i in so.read():
ssh = i.replace("你", "我")
wo.write(ssh)
os.remove("文件")
os.rename("文件_os", "文件")
以上实例,只是把读取文件操作换成for循环来读取而已